using Microsoft.Extensions.DependencyInjection;

using System.Reflection;

/// <summary>
/// 依赖注入扫描器
/// </summary>
public static class DependencyScanner
{
    /// <summary>
    /// 扫描程序集并注册服务
    /// </summary>
    /// <param name="services">服务集合</param>
    /// <param name="assemblies">程序集集合</param>
    /// <returns>服务集合</returns>
    public static IServiceCollection AddDependencyInjection(this IServiceCollection services, params Assembly[] assemblies)
    {
        // 获取所有程序集
        var allAssemblies = GetAllAssemblies();

        // 查找所有具有依赖注入特性的类型
        var types = allAssemblies
            .SelectMany(a => a.GetTypes())
            .Where(u => u.IsClass && !u.IsAbstract &&
                    typeof(IDependencyInjection).IsAssignableFrom(u)
                  )
            .ToList();

        // 获取生命周期接口
        var lifetimeInterfaces = new[] { typeof(ITransient), typeof(IScoped), typeof(ISingleton) };

        // 注册服务
        foreach (var type in types)
        {
            // 获取继承接口
            var interfaces = type.GetInterfaces();

            var dependencyType = interfaces.Last(u => lifetimeInterfaces.Contains(u));
            // 获取可注入接口
            var canInjectInterfaces = interfaces.Where(u =>
                             u != typeof(IDisposable)
                            && u != typeof(IAsyncDisposable)
                            && u != typeof(IDependencyInjection)
                            && !lifetimeInterfaces.Contains(u)
                            && allAssemblies.Contains(u.Assembly)
                            && (
                                (!type.IsGenericType && !u.IsGenericType)
                                || (type.IsGenericType && u.IsGenericType && type.GetGenericArguments().Length == u.GetGenericArguments().Length))
                            );

            RegisterService(services, dependencyType, type, canInjectInterfaces);
        }

        return services;
    }

    /// <summary>
    /// 获取所有程序集
    /// </summary>
    /// <returns>程序集集合</returns>
    private static Assembly[] GetAllAssemblies()
    {
        var assemblies = new List<Assembly>();
        // 获取所有程序集
        assemblies = AppDomain.CurrentDomain.GetAssemblies()
                                .Where(ass =>
                                        !ass.FullName.StartsWith(nameof(System))
                                        && !ass.FullName.StartsWith(nameof(Microsoft))
                                        && !ass.FullName.StartsWith("netstandard"))
                                .Distinct().ToList();
        // 添加入口程序集
        var entryAssembly = Assembly.GetEntryAssembly();
        if (entryAssembly != null && !assemblies.Contains(entryAssembly))
        {
            assemblies.Add(entryAssembly);
        }

        return assemblies.ToArray();
    }

    /// <summary>
    /// 注册服务
    /// </summary>
    /// <param name="services"></param>
    /// <param name="dependencyType"></param>
    /// <param name="type"></param>
    /// <param name="inters"></param>
    private static void RegisterService(IServiceCollection services, Type dependencyType, Type type, IEnumerable<Type> inters)
    {
        // 获取服务生命周期
        var lifetime = TryGetServiceLifetime(dependencyType);

        // 首先将类型本身注册为服务，以兼容没有接口的情况
        var fixedSelfType = type;
        services.Add(ServiceDescriptor.Describe(fixedSelfType, fixedSelfType, lifetime));

        foreach (var item in inters)
        {
            // 处理服务类型
            var fixedType = type;
            // 处理接口类型
            var fixedInter = item;

            // 如果是泛型类型，需要特殊处理
            if (type.IsGenericType && item != null && item.IsGenericType)
            {
                // 确保接口和实现类的泛型参数数量匹配
                if (type.GetGenericArguments().Length == item.GetGenericArguments().Length)
                {
                    // 获取泛型定义类型
                    fixedType = type.GetGenericTypeDefinition();
                    fixedInter = item.GetGenericTypeDefinition();
                }
            }

            //注册服务
            services.Add(ServiceDescriptor.Describe(fixedInter, fixedType, lifetime));
        }
    }

    /// <summary>
    /// 获取服务生命周期
    /// </summary>
    /// <param name="dependencyType"></param>
    /// <returns></returns>
    /// <exception cref="InvalidCastException"></exception>
    private static ServiceLifetime TryGetServiceLifetime(Type dependencyType)
    {
        if (dependencyType == typeof(ITransient))
        {
            return ServiceLifetime.Transient;
        }
        else if (dependencyType == typeof(IScoped))
        {
            return ServiceLifetime.Scoped;
        }
        else if (dependencyType == typeof(ISingleton))
        {
            return ServiceLifetime.Singleton;
        }
        else
        {
            throw new InvalidCastException("Invalid service registration lifetime.");
        }
    }
}